<?php
/**
 * Enter description here ...
 * @author admin
 *
 */
class Update_Model_Database_Manager{

	/**
	 * Name of version control table
	 * @var string
	 */
	private $table_name='update_db_version';
	/**
	 * DB Adapter
	 *
	 */
	private $db;

	/**
	 * DB Update files array
	 * @var array
	 */
	private $files=false;

	public function __construct($db=false){
		if($db==false){
			$this->setDb(Zend_Db_Table::getDefaultAdapter());
		}else{
			$this->setDb($db);
		}
	}
	public function setDb($db){
		$this->db=$db;
	}

	public function getDb(){
		return $this->db;
	}




	private function processFile($filename,$classname,$direction){
		require_once $filename;
		if (!class_exists($classname, false)) {
			$res=false;
			throw new Zend_Exception("Could not find class '$classname' in file '$filename'");
		}
		try{
		$class = new $classname($this->db);
		}
		catch (Exeption $e){
			throw new Zend_Exception('Cant find class '.$classname);

		}
		try{
		$class->$direction();
		}catch (Exeption $e){
			throw $e;

		}
		$class=null;
	}


	private function updateVersion($table,$version){
		if($this->versionTableExist()){
			$this->current_version[$table]['current_version']=$version;
			$res=$this->db->query('SELECT version FROM '.$this->table_name." WHERE table_name='".$table."'")->fetchAll();

			if(isset($res[0]['version'])){
				$sql="UPDATE ".$this->table_name." SET version ='".$version."',update_date='".date('Y-m-d H:i:s')."' WHERE table_name='".$table."'";
				$this->db->query($sql);
			}else{
				$sql='INSERT INTO update_db_version (table_name,version,update_date)
							VALUES(
			  				"'.$table.'",
			  				"'.$version.'",
			  				"'.date('Y-m-d H:i:s').'"
							);';
				$this->db->query($sql);
			}
		}

	}


	public function upgrade($table,$new_version=false){
		if($this->files==false){
			$this->loadUpdates();
		}

		if($new_version==false||$new_version<=0){
			$new_version=$this->files[$table]['new_version'];
		}

		$res=true;

		$current_version=$this->files[$table]['current_version'];
		$current_version++;

		$this->db->beginTransaction();
		try {
			for ($i=$current_version;$i<=$new_version;$i++){

				$name=$table.'_'.$i.'.php';
				if(isset($this->files[$table][$i]['filename'])){

					$filename=$this->files[$table][$i]['filename'];

					if(file_exists($filename)){
						$this->processFile($filename,$this->files[$table][$i]['class'],'up');
						$this->updateVersion($table, $i);
					}else{
						$res=false;
						throw new Zend_Exception('File "'.$name.'" was not found' );
					}

				}else{
					$res=false;
					throw new Zend_Exception('File "'.$name.'" was not found' );
				}
			}

		} catch (Exception $e) {
			$res=false;
			$this->db->rollBack();
			echo $e->getTraceAsString();
		}

		if($res!=false){
			$this->db->commit();
		}

	}

	/**
	 * Откат одной таблицы
	 * @param string $table имя таблицы
	 * @param int $new_version
	 * @throws Zend_Exception
	 */
	public function downgrade($table,$new_version=false){
		if($this->files==false){
			$this->loadUpdates();
		}

		if($new_version==false||$new_version<=0){
			$new_version=1;
		}

		$res=true;

		$current_version=$this->files[$table]['current_version'];

		echo $current_version." | ".$new_version;

		$this->db->beginTransaction();
		try {
			for ($i=$current_version;$i>=$new_version;$i--){
				echo $i;
				$name=$table.'_'.$i.'.php';
				if(isset($this->files[$table][$i]['filename'])){

					$filename=$this->files[$table][$i]['filename'];

					if(file_exists($filename)){
						$this->processFile($filename,$this->files[$table][$i]['class'],'down');
						$this->updateVersion($table, $i);
					}else{
						$res=false;
						throw new Zend_Exception('File "'.$name.'" was not found' );
					}

				}else{
					$res=false;
					throw new Zend_Exception('File "'.$name.'" was not found' );
				}
			}

		} catch (Exception $e) {
			$res=false;
			$this->db->rollBack();
			throw $e;
		}

		if($res!=false){
			$this->db->commit();
		}

	}

	/**
	 * Проверка существования версионной таблицы в БД
	 * @return boolean
	 */
	private function versionTableExist(){
		try{
			$current_version=$this->db->query('SELECT * FROM '.$this->table_name)->fetchAll();
			return true;
		}catch (Exception $e){
			return false;
		}
	}


	/**
	 * Загрузка файлов обновлений и данных из бд в массив, для дальнейшей обработки
	 */
	private function loadUpdates() {
		$cfg = Zend_Registry::get ( 'cnf' );
		$dir = $cfg->resources->frontController->moduleDirectory;
		$dir=$dir->toArray();
		$modules = array ();

		foreach ( $dir as $d ) {
			$modules [$d] = scandir ( $d );
		}

		$files = array ();

		foreach ( $modules as $dir => $mods ) {
			foreach ( $mods as $module ) {
				$db_dir = $dir . '/' . $module . '/db/';
				if (is_dir($db_dir)&& is_readable($db_dir)) {
					$d = dir($db_dir);
					while (false !== ($entry = $d->read())) {
						if (preg_match('/^(.*)\_([0-9]+)\.php/i', $entry, $matches) ) {
							$versionNumber = (int)$matches[2];
							$className = $matches[1];
							$files[$className][$versionNumber] = array(
                        		'version'=>$versionNumber,
								'class'=>$className.'_'.$versionNumber,
                        		'table_name'=>$className,
								'filename'=>$dir . '/' . $module . '/db/'.$entry,

							);
							$files[$className]['current_version']=0;

						}
					}
					$d->close();
				}

			}
		}
		if(sizeof($files)>0){
			foreach ($files as $table=>$versions){
				$update_version=max( array_keys( $versions ));
				ksort($files[$table]);
				$files[$table]['new_version']=$update_version;
			}
		}


		if($this->versionTableExist()){
			$current_version=$this->db->query('SELECT * FROM '.$this->table_name)->fetchAll();
		}else{
			$current_version=array();
		}
		if(sizeof($current_version>0))
		foreach ($current_version as $row ){
			$files[$row['table_name']]['current_version']=$row['version'];
		}
		$this->files=$files;
	}


	/**
	 * Обновление всех найденных таблиц
	 */
	public function upgradeAll($maxVerion=false){
		$this->loadUpdates();


		if(sizeof($this->files)>0){
			foreach ($this->files as $table=>$versions){

				if(
				$this->files[$table]['new_version'] >
				$this->files[$table]['current_version']
				){

					$this->upgrade($table,$maxVerion);
				}

			}
		}

	}

	/**
	 * Откат всех таблиц
	 */
	public function downgradeAll($minVersion){
		$this->loadUpdates();
		if(sizeof($this->files)>0){
			foreach ($this->files as $table=>$versions){

				if($this->files[$table]['new_version'] <=$this->files[$table]['current_version']){
					if($table!=$this->table_name && !$table=='core');
					$this->downgrade($table,$minVersion);
				}

			}
		}
	}

	public function findUpdates(){
		$this->loadUpdates();
		return $this->files;
	}


}